#!/bin/bash
#===============================================================================
#
#          FILE: install.sh
#
#         USAGE: ./install.sh
#
#   DESCRIPTION: 
#
#       OPTIONS: ---
#  REQUIREMENTS: ---
#          BUGS: ---
#         NOTES: ---
#        AUTHOR: zimingzpp (zhang), zimingzpp@qq.com
#  ORGANIZATION: 
#       CREATED: 09/08/20 09:45:29
#      REVISION:  ---
#===============================================================================

set -o nounset                                  # Treat unset variables as an error

#-------------------------------------------------------------------------------
#设置PATH 
#-------------------------------------------------------------------------------
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

cur_dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

#-------------------------------------------------------------------------------
#include函数检测脚本是否存在 
#-------------------------------------------------------------------------------
include(){
    local include=${1}
    if [[ -s ${cur_dir}/include/${include}.sh ]];then
        . ${cur_dir}/include/${include}.sh
    else
        echo "Error: ${cur_dir}/include/${include}.sh not found, shell can not be executed."
        exit 1
    fi
}

#-------------------------------------------------------------------------------
#颜色打印 
#-------------------------------------------------------------------------------
_red(){
    printf '\033[1;31;31m%b\033[0m' "$1"
}

_green(){
    printf '\033[1;31;32m%b\033[0m' "$1"
}

_yellow(){
    printf '\033[1;31;33m%b\033[0m' "$1"
}

_printargs(){
    printf -- "%s" "$1"
    printf "\n"
}

_info(){
    _printargs "$@"
}

_warn(){
    _yellow "$1"
    printf "\n"
}

#-------------------------------------------------------------------------------
#打印错误信息 
#-------------------------------------------------------------------------------
_error(){
    _red "$1"
    printf "\n"
    exit 1
}

#-------------------------------------------------------------------------------
#获取有效输入 
#-------------------------------------------------------------------------------
get_valid_valname(){
    local val="$1"
    local new_val=$(eval echo $val | sed 's/[-.]/_/g')
    echo ${new_val}
}

#-------------------------------------------------------------------------------
# 
#-------------------------------------------------------------------------------
get_hint(){
    local val="$1"
    local new_val=$(get_valid_valname $val)
    eval echo "\$hint_${new_val}"
}

#-------------------------------------------------------------------------------
#获取IP地址 
#-------------------------------------------------------------------------------
get_ip(){
    local ipv4=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
        egrep -v "^169|^127|(\.0|\.1|255)$" | head -n 1 )
    [ -z "${ipv4}" ] && ipv4=$( wget -qO- -t1 -T2 ipv4.icanhazip.com )
    [ -z "${ipv4}" ] && ipv4=$( wget -qO- -t1 -T2 ipinfo.io/ip )
    printf -- "%s" "${ipv4}"
}

#-------------------------------------------------------------------------------
#检测系统 
#-------------------------------------------------------------------------------
check_sys(){
    local checkType="$1"
    local value="$2"
    local release=''
    local systemPackage=''
    
    if [[ -f /etc/redhat-release ]] ; then
        release="centos"
        systemPackage="yum"
    elif grep -Eqi "debian" /etc/issue ; then
        release="debian"
        systemPackage="apt"
    elif grep -Eqi "ubuntu" /etc/issue ; then
        release="ubuntu"
        systemPackage="apt"
    elif grep -Eqi "centos|red hat|redhat" /etc/issue ; then
        release="centos"
        systemPackage="yum"
    elif grep -Eqi "debian" /proc/version ; then
        release="debian"
        systemPackage="apt"
    elif grep -Eqi "ubuntu" /proc/version ; then
        release="ubuntu"
        systemPackage="apt"
    elif grep -Eqi "centos|red hat|redhat" /proc/version ; then
        release="centos"
        systemPackage="yum"
    fi

    if [[ "${checkType}" == "sysRelease" ]] ; then
        if [ "${value}" == "${release}" ]; then
            return 0
        else
            return 1
        fi
    elif [[ "${checkType}" == "packageManager" ]] ; then
        if [  "${value}" == "${systemPackage}" ]; then
           return 0
        else
            return 1
        fi
    fi
}

#-------------------------------------------------------------------------------
#查询版本 
#-------------------------------------------------------------------------------
versionget(){
    if [[ -s /etc/redhat-release ]]; then
        grep -oE "[0-9.]+" /etc/redhat-release
    else
        grep -oE "[0-9.]+" /etc/issue
    fi
}

#-------------------------------------------------------------------------------
#获取系统版本号 
#-------------------------------------------------------------------------------
get_opsy(){
    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}

#-------------------------------------------------------------------------------
#获得Centos系统版本 
#-------------------------------------------------------------------------------
get_centosversion(){
    if check_sys sysRelease centos ; then
        local version="$(versionget)"
        echo $(version%%.*)
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#获得debian版本信息
#-------------------------------------------------------------------------------
get_debianversion(){
    if check_sys sysRelease debian; then
        local version=$( get_opsy )
        local main_ver=$( echo ${version} | grep -oE  "[0-9.]+")
        echo ${main_ver%%.*}
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#获得Ubuntu版本信息 
#-------------------------------------------------------------------------------
get_ubuntuversion(){
    if check_sys sysRelease ubuntu; then
        local version=$( get_opsy )
        local main_ver=$( echo ${version} | grep -oE  "[0-9.]+")
        echo ${main_ver%%.*}
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#检查系统 
#-------------------------------------------------------------------------------
check_os(){
    is_support_flg=0
    if check_sys packageManager yum|| check_sys packageManager apt; then
        # 不支持低于6.0的Centos、低于8的Debian和低于14的Ubuntu
        
        if [ -n "$(get_centosversion)" ] && [ $(get_centosversion) -lt 6 ] ; then
            is_support_flg=1
        fi
        if [ -n "$(get_debianversion)" ] && [ $(get_debianversion) -lt 8 ] ; then
            is_support_flg=1
        fi
        if [ -n "$(get_ubuntuversion)" ] && [ $(get_ubuntuversion) -lt 14 ] ; then
            is_support_flg=1
        fi
    else
        is_support_flg=1
    fi
    if [ ${is_support_flg} -eq 1 ] ; then
        echo "不支持的系统。请更换系统为Centos 6+或Debian 8+或Ubuntu 14+"
        exit 1
    fi
}

#-------------------------------------------------------------------------------
#查询系统信息 
#-------------------------------------------------------------------------------
get_os_info(){
    cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo )
    freq=$( awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    tram=$( free -m | awk '/Mem/ {print $2}' )
    swap=$( free -m | awk '/Swap/ {print $2}' )
    up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60;d=$1%60} {printf("%ddays, %d:%d:%d\n",a,b,c,d)}' /proc/uptime )
    load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' )
    opsy=$( get_opsy )
    arch=$( uname -m )
    lbit=$( getconf LONG_BIT )
    host=$( hostname )
    kern=$( uname -r )
    ramsum=$( expr $tram + $swap )
}

#-------------------------------------------------------------------------------
#检测系统配置 
#-------------------------------------------------------------------------------
check_ram(){
    get_os_info
    if [ ${ramsum} -lt 480 ]; then
        _error "Not enough memory. The LAMP installation needs memory: ${tram}MB*RAM + ${swap}MB*SWAP >= 480MB"
    fi
    [ ${ramsum} -lt 1025 ] && disable_fileinfo="--disable-fileinfo" || disable_fileinfo=""
}

#-------------------------------------------------------------------------------
#显示系统配置信息 
#-------------------------------------------------------------------------------
display_os_info(){
    clear
    echo
    echo "+-------------------------------------------------------------------+"
    echo "| Auto Install LAMP(Linux + Apache + MySQL/MariaDB + PHP )          |"
    echo "| Website: https://lamp.sh                                          |"
    echo "| Author : Teddysun <i@teddysun.com>                                |"
    echo "+-------------------------------------------------------------------+"
    echo
    echo "--------------------- System Information ----------------------------"
    echo
    echo "CPU model            : ${cname}"
    echo "Number of cores      : ${cores}"
    echo "CPU frequency        : ${freq} MHz"
    echo "Total amount of ram  : ${tram} MB"
    echo "Total amount of swap : ${swap} MB"
    echo "System uptime        : ${up}"
    echo "Load average         : ${load}"
    echo "OS                   : ${opsy}"
    echo "Arch                 : ${arch} (${lbit} Bit)"
    echo "Kernel               : ${kern}"
    echo "Hostname             : ${host}"
    echo "IPv4 address         : $(get_ip)"
    echo
    echo "---------------------------------------------------------------------"
}

#-------------------------------------------------------------------------------
#预安装 
#-------------------------------------------------------------------------------
lamp_preinstall(){
    apache_preinstall_settings
    mysql_preinstall_settings
    php_preinstall_settings
    php_modules_preinstall_settings
    phpmyadmin_preinstall_settings
    kodexplorer_preinstall_settings
}

#-------------------------------------------------------------------------------
#安装菜单 
#-------------------------------------------------------------------------------
display_menu(){
    local soft="$1"
    local default="$2"
    eval local arr=(\${${soft}_arr[@]})
#    eval local arr=(\${${soft}_arr[@]})
    local default_prompt
    if [[ "$default" != "" ]]; then
        if [[ "$default" == "last" ]]; then
            default=${#arr[@]}
        fi
        default_prompt="(default ${arr[$default-1]})"
    fi
    local pick
    local hint
    local vname
    local prompt="which ${soft} you'd select ${default_prompt}: "

    while true; do
        echo -e "\n-------------------------- ${soft} setting ---------------------------\n"
        for ((i=1;i<=${#arr[@]};i++ )); do
            vname="$(get_valid_valname ${arr[$i-1]})"
            hint="$(get_hint $vname)"
            [[ "$hint" == "" ]] && hint="${arr[$i-1]}"
            _info "$(_green ${i}). $hint"
        done
        echo
        read -p "${prompt}" pick
        if [[ "$pick" == "" && "$default" != "" ]]; then
            pick=${default}
            break
        fi
        if ! is_digit "$pick"; then
            prompt="Input error, please only input a number: "
            continue
        fi
        if [[ "$pick" -lt 1 || "$pick" -gt ${#arr[@]} ]]; then
            prompt="Input error, please input a number between 1 and ${#arr[@]}: "
            continue
        fi
        break
    done

    eval ${soft}=${arr[$pick-1]}
    vname="$(get_valid_valname ${arr[$pick-1]})"
    hint="$(get_hint $vname)"
    [[ "$hint" == "" ]] && hint="${arr[$pick-1]}"
    echo -e "\nyour selection: $hint"
}

display_menu_multi(){
    local soft="$1"
    local default="$2"
    eval local arr=(\${${soft}_arr[@]})
    local arr_len=${#arr[@]}
    local pick
    local correct=true
    local prompt
    local vname
    local hint
    local default_prompt
    if [[ "$default" != "" ]]; then
        if [[ "$default" == "last" ]]; then
            default=${arr_len}
        fi
        default_prompt="(default ${arr[$default-1]})"
        
    fi
    prompt="Please input one or more number between 1 and ${arr_len} ${default_prompt} (for example: 1 2 3): "

    echo -e "\n-------------------------- ${soft} install --------------------------\n"
    for ((i=1;i<=${arr_len};i++ )); do
        vname="$(get_valid_valname ${arr[$i-1]})"
        hint="$(get_hint $vname)"
        [[ "$hint" == "" ]] && hint="${arr[$i-1]}"
        _info "$(_green ${i}). $hint"
    done
    echo
    while true; do
        read -p "${prompt}" pick
        pick=(${pick})
        eval unset ${soft}_install
        if [[ "$pick" == "" ]]; then
            if [[ "$default" == "" ]]; then
                echo "Input can not be empty, please reinput."
                continue
            else
                eval ${soft}_install="${arr[$default-1]}"
                break
            fi
        fi

        for j in ${pick[@]}; do
            if ! is_digit "$j"; then
                echo "Input error, please only input a number."
                correct=false
                break 1
            fi
            if [[ "$j" -lt 1 || "$j" -gt ${arr_len} ]]; then
                echo "Input error, please input one or more number between 1 and ${arr_len}${default_prompt}."
                correct=false
                break 1
            fi
            if [ "${arr[$j-1]}" == "do_not_install" ]; then
                eval ${soft}_install="do_not_install"
                break 2
            fi
            eval ${soft}_install="\"\$${soft}_install ${arr[$j-1]}\""
            correct=true
        done
        [[ "$correct" == true ]] && break
    done

    echo
    eval echo -e "your selection: \$${soft}_install"
}
#-------------------------------------------------------------------------------
#apache预安装设置 
#-------------------------------------------------------------------------------


apache_preinstall_settings(){
    display_menu apache 1
    if [ "${apache}" == "do_not_install" ]; then
        apache_modules_install="do_not_install"
    else
        display_menu_multi apache_modules last
    fi
}

main(){
check_os
check_ram
display_os_info
lamp_preinstall
}
#-------------------------------------------------------------------------------
#脚本开始执行 
#-------------------------------------------------------------------------------
include config
load_config

main




